package com.dwxt.gateway.config;

import com.dwxt.common.base.BaseResult;
import com.dwxt.common.base.StatusCode;
import com.dwxt.common.util.DateUtils;
import com.dwxt.common.util.JwtUtils;
import com.dwxt.gateway.feign.AdminUserService;
import com.dwxt.gateway.feign.AppUserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 描述: JwtToken 过滤器
 *
 * @Auther: lzx
 * @Date: 2019/7/9 15:49
 */
@Component
@Slf4j
public class JwtTokenFilter implements GlobalFilter, Ordered {

    @Autowired
    private AdminUserService adminUserService;

    @Autowired
    private AppUserService appUserService;

    private static List<String> skipAuthUrls = new ArrayList<>();

    private ObjectMapper objectMapper;

    public JwtTokenFilter(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    static {
        skipAuthUrls.add("/admin/user/login");
        skipAuthUrls.add("/admin/user/selectUserById");
        skipAuthUrls.add("/cms/user/login");
        skipAuthUrls.add("/cms/supervisor/login");
        skipAuthUrls.add("/cms/user/register");
        skipAuthUrls.add("/cms/user/sendVerificationCode");
        skipAuthUrls.add("/cms/user/resetPassword");
        skipAuthUrls.add("/cms/user/confirmHouseHead");

        //客服
        skipAuthUrls.add("/mall/customer/selectPhone");

        //分类桶
        skipAuthUrls.add("/cms/fl/ws");
        skipAuthUrls.add("/cms/fl/record");
        skipAuthUrls.add("/cms/fl/verification");
        //售卖机
        skipAuthUrls.add("/cms/smj/ws");
        skipAuthUrls.add("/cms/smj/breakdown");
        skipAuthUrls.add("/cms/smj/netpay");
        skipAuthUrls.add("/cms/smj/newReceive");
        skipAuthUrls.add("/cms/smj/zfbCallback");
        skipAuthUrls.add("/cms/smj/wxCallback");

        skipAuthUrls.add("/mall/zfb/notifyUrl");
        skipAuthUrls.add("/mall/wx/callback");
        //赛事回调
        skipAuthUrls.add("/race/payBack/zfb/callback");
        skipAuthUrls.add("/race/payBack/wx/callback");
        //可视化
        skipAuthUrls.add("/cms/admin/visual/totalOfUser");
        skipAuthUrls.add("/cms/admin/visual/trashRecordNow");
        skipAuthUrls.add("/cms/admin/visual/totalMonthIntegral");
        skipAuthUrls.add("/cms/admin/visual/equipmentStatus");
        skipAuthUrls.add("/cms/admin/visual/equipmentNumbers");
        skipAuthUrls.add("/cms/admin/img/pageList");
        //设备监控
        skipAuthUrls.add("/cms/broadcast/getIncludeChild");

        //ios上架
        skipAuthUrls.add("/cms/information/get");
        skipAuthUrls.add("/cms/broadcast/hot");
        skipAuthUrls.add("/cms/broadcast/hotVideo");
        skipAuthUrls.add("/cms/broadcast/getColumeType");
        skipAuthUrls.add("/cms/broadcast/getIncludeChild");
        skipAuthUrls.add("/cms/information/viewPaper");
        skipAuthUrls.add("/cms/ad/getAdType");
        skipAuthUrls.add("/cms/information/get");
        skipAuthUrls.add("/cms/broadcast/broadcastByColumnId");
        skipAuthUrls.add("/cms/broadcast/broadcastDetailAndCorrelation");
        skipAuthUrls.add("/cms/information/detail");
        skipAuthUrls.add("/cms/information/getRecommend");
        skipAuthUrls.add("/cms/userAction/share");

        skipAuthUrls.add("/mall/product/selectProductListByType");
        skipAuthUrls.add("/mall/product/selectModuleProductList");
        skipAuthUrls.add("/mall/promotion/selectPromotionProduct");
        skipAuthUrls.add("/mall/product/selectProductById");
        skipAuthUrls.add("/mall/product/selectProductByName");
        skipAuthUrls.add("/mall/attr/selectProductCategoryByModule");
        skipAuthUrls.add("/mall/order/selectOrderGraph");
        skipAuthUrls.add("/mall/order/selectOrderByProductId");
        skipAuthUrls.add("/mall/order/selectProductByKey");


        skipAuthUrls.add("/cms/graph/user");
        skipAuthUrls.add("/cms/graph/selectUserGraphEveryDay");
        skipAuthUrls.add("/cms/graph/selectIntegralGraph");
        skipAuthUrls.add("/stadium/stadiumGraph");
        skipAuthUrls.add("/stadium/stadiumOrderMonthGraph");
        skipAuthUrls.add("/race/raceList/selectRaceList");
        skipAuthUrls.add("/cms/user/selectUserCount");


        /*解析设备*/
        skipAuthUrls.add("/cdms/receive/api/data");
        skipAuthUrls.add("/cdms/parse/receiveData");
        skipAuthUrls.add("/cdms/parse/getBloodPressureAndBloodSugar");
        skipAuthUrls.add("/cdms/parse/getBloodPressureAndBloodSugarBest");
        skipAuthUrls.add("/cdms/heartVoice/data");
//        skipAuthUrls.add("/cdms/health/selectHealthRecordPage");
//        skipAuthUrls.add("/cdms/health/selectCountFromHealthRecord");
//        skipAuthUrls.add("/cdms/health/selectAllWarnPage");
//        skipAuthUrls.add("/cdms/health/selectAllWarnGraphHour");
//        skipAuthUrls.add("/cdms/health/selectAllWarnGraphMonth");
//        skipAuthUrls.add("/cdms/parse/pageLocDataViewList");
        skipAuthUrls.add("/cdms/user/login");
        skipAuthUrls.add("/cdms/user/getVerify");
        skipAuthUrls.add("/cdms/witheart/receiveData");
        skipAuthUrls.add("/cdms/yeYing/receiveData");
        skipAuthUrls.add("/cdms/user/wxLogin");
        skipAuthUrls.add("/cdms/user/sendCode");
        skipAuthUrls.add("/cdms/user/codeLogin");
        skipAuthUrls.add("/cdms/small/getQrCode");
        skipAuthUrls.add("/cdms/customer/insertCustomerZT");
        skipAuthUrls.add("/cdms/healthReport/select");
        skipAuthUrls.add("/cdms/authentication/wx");
        skipAuthUrls.add("/cdms/health/selectCountForCommunity");
//        skipAuthUrls.add("/cdms/health/countNotHandleWarn");


        //看板接口
        skipAuthUrls.add("/cms/admin/operationManager/targerMonthData");

        //watch接口
        skipAuthUrls.add("/cdms/watch/receiveData");

        //手表接口
        skipAuthUrls.add("/cdms/oufu/receiveData");
        skipAuthUrls.add("/cdms/oufu/receiveDataZT");


        //导出
        /*skipAuthUrls.add("/cms/admin/trashCan/recordExport");
        skipAuthUrls.add("/cms/user/export");
        skipAuthUrls.add("/mall/order/exportOrder");*/

    }

    /**
     * 过滤器
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //小程序
        ServerHttpRequest request = exchange.getRequest();
        String isMin = request.getHeaders().getFirst("isMin");
        //boolean isMin = Boolean.parseBoolean(isMin);
        if (StringUtils.isNotBlank(isMin) && Boolean.parseBoolean(isMin)) {
            return chain.filter(exchange);
        }
        String url = request.getURI().getPath();
        log.info(DateUtils.formatTime(new Date()) + ":" + request.getRemoteAddress().getAddress() + ":" + url);
        //跳过不需要验证的路径
        if (skipAuthUrls.contains(url) || url.contains("websocket")) {
            return chain.filter(exchange);
        }

        //获取token
        String token = request.getHeaders().getFirst("Authorization");
        ServerHttpResponse resp = exchange.getResponse();
        if (StringUtils.isBlank(token)) {
            log.error("1");
            return authErro(resp, StatusCode.PERMISSION_FAIL);
        } else {
            //有token
            try {
                String subject = JwtUtils.getSubject(token);
                String[] userIds = subject.split(",");
                if (!"back".equalsIgnoreCase(userIds[1])) {
                    BaseResult baseResult = appUserService.selectUserByKey(userIds[0]);
                    if (baseResult.getData() != null) {
                        return chain.filter(exchange);
                    } else {
                        log.error("5");
                        return authErro(resp, StatusCode.PERMISSION_FAIL);
                    }
                } else {
                    /*List<String> list = adminUserService.selectPermissionUrl(Integer.parseInt(subject.substring(0, subject.indexOf(","))));
                    if(list.contains(url)){
                        return chain.filter(exchange);
                    }else {
                        return authErro(resp, StatusCode.PERMISSION_FAIL);
                    }*/
                    return chain.filter(exchange);
                }

            } catch (ExpiredJwtException e) {
                log.error("path", url);
                log.error(e.getMessage(), e);
                if (e.getMessage().contains("Allowed clock skew")) {
                    log.error("2");
                    return authErro(resp, StatusCode.TOKEN_EXPIRED);
                }
            } catch (Exception e) {
                log.error("path", url);
                log.error(token, e);
                log.error("3");
                return authErro(resp, StatusCode.PERMISSION_FAIL);
            }
            log.error("path", url);
            log.error("4");
            return authErro(resp, StatusCode.PERMISSION_FAIL);
        }
    }

    /**
     * 认证错误输出
     *
     * @param resp       响应对象
     * @param statusCode 错误信息
     * @return
     */
    private Mono<Void> authErro(ServerHttpResponse resp, StatusCode statusCode) {
        //resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        //ReturnData<String> returnData = new ReturnData<>(org.apache.http.HttpStatus.SC_UNAUTHORIZED, mess, mess);
        BaseResult result = BaseResult.build(statusCode);
        String returnStr = "";
        try {
            returnStr = objectMapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(), e);
        }
        DataBuffer buffer = resp.bufferFactory().wrap(returnStr.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return -100;
    }
}

